import json
import re

from django.contrib.auth import authenticate, login, logout
from django.http import JsonResponse
from django.middleware.csrf import get_token
from django.views import View
from django_redis import get_redis_connection

from meiduo_mall.utils.mixins import LoginRequiredMixin
from users.models import User


class UsernamesView(View):
    ''' 判断用户名是否重复注册
    使用count()在查询数据库时判断值为 0 或 1,
    1 : 存在
    0 : 不存在
    '''
    def get(self, request, username):
        try:
            count = User.objects.filter(username=username).count()
        except Exception as e:
            return JsonResponse({
                'code': 400,
                'message': '数据库操作失败'
            })

        return JsonResponse({
            'code': 0,
            'message': 'OK',
            'count': count
        })


class MobilesView(View):
    def get(self, request, mobile):
        try:
            count = User.objects.filter(mobile=mobile).count()
        except Exception as e:
            return JsonResponse({
                'code': 400,
                'message': '数据库操作失败'
            })
        return JsonResponse({
            'code': 0,
            'message': 'OK',
            'count': count
        })


class RegisterView(View):
    def post(self, request):
        ''' 用户注册信息保存
        ① 获取页面数据并进行校验
        ② 保存注册数据
        ③ 保持登录状态
        ④ 返回响应结果
        '''
        req_data = json.loads(request.body)

        username = req_data.get('username')
        password = req_data.get('password')
        password2 = req_data.get('password2')
        mobile = req_data.get('mobile')
        sms_code = req_data.get('sms_code')
        allow = req_data.get('allow')

        if not all([username, password, password2, mobile, allow, sms_code]):
            return JsonResponse({
                'code': 400,
                'message': '缺少必传参数'
            })
        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return JsonResponse({'code': 400,
                                 'message': 'username格式错误'})

        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            return JsonResponse({'code': 400,
                                 'message': 'password格式错误'})

        if password != password2:
            return JsonResponse({'code': 400,
                                 'message': '两次密码不一致'})

        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return JsonResponse({'code': 400,
                                 'message': '手机号格式错误'})

        if not allow:
            return JsonResponse({'code': 400,
                                 'message': '请同意协议!'})

        redis_conn = get_redis_connection('verify_code')
        sms_code_redis = redis_conn.get('sms_%s' % mobile)

        if not sms_code_redis:
            return JsonResponse({
                'code': 400,
                'message': '短信验证码过期'
            })

        if sms_code != sms_code_redis:
            return JsonResponse({
                'code': 400,
                'message': '短信验证码错误'
            })

        try:
            user = User.objects.create_user(username=username,
                                            password=password,
                                            mobile=mobile)
        except Exception as e:
            return JsonResponse({
                'code': 400,
                'message': '数据库保存错误'
            })

        # 登录状态保持(login方法)
        login(request, user)

        response = JsonResponse({
            'code': 0,
            'message': 'OK'
        })

        """
        保存用户登录状态并在首页展示
        ① 登录状态在注册和登录时将信息保存在cookie中
        ② 在登陆后使用前端访问cookie获取username信息后从cookie中取出
        """
        response.set_cookie('username', user.username, max_age= 3600 * 24 * 14)
        return response


class CRSFTokenView(View):
    def get(self, request):
        ''' 获取crsftoken的 API 接口
        进行CSRF保护验证时，Django框架还会从客户端请求头中获取 X-CSRFToken 这个请求头的值，
        如果是post表单请求方式，会优先从post表单数据中获取 csrfmiddlewaretoken 的值
        将获取到的 csrftoken 的值和 X-CSRFToken 的值进行结合验证，
        如果一致(不一定对比是否相同)，则CSRF校验通过，否则校验失败
        '''
        csrf_token = get_token(request)

        return JsonResponse({
            'code': 0,
            'message': 'OK',
            'csrf_token': csrf_token
        })


class LoginView(View):
    def post(self, request):
        req_data = json.loads(request.body)
        username = req_data.get('username')
        password = req_data.get('password')
        remember = req_data.get('remember')

        if not all([username, password]):
            return JsonResponse({
                'code': 400,
                'message': '缺少必传参数'
            })
        # authenticate 底层代码有一个 USERNAME_FILED 的属性,他的默认值是username
        # 若想实现用户名密码同时登录, 判断将 USERNAME_FILED 默认值改成 mobile
        if re.match(r'^1[3-9]\d{9}$', username):
            User.USERNAME_FIELD = 'mobile'
        else:
            User.USERNAME_FIELD = 'username'

        # 判断用户名密码是否正确(authenticate)
        user = authenticate(username=username, password=password)

        if user is None:
            return JsonResponse({
                'code': 400,
                'message': '用户名或密码错误'
            })

        # 保存用户状态
        login(request, user)

        if not remember:
            request.session.set_expiry(0)

        response = JsonResponse({
            'code': 0,
            'message': 'OK'
        })
        response.set_cookie('username', user.username, 14 * 3600 * 24)
        return response


class LogoutView(View):
    def delete(self, request):
        '''用户退出登录
        logout 是django中封装好的清除登录用户session数据的过程
        '''
        logout(request)
        response = JsonResponse({
            'code': 0,
            'message': 'OK'
        })
        response.delete_cookie('username')

        return response


class UserInfoView(LoginRequiredMixin,View):
    def get(self, request):
        '''个人用户信息
        在个人中心页面需要展示个人信息(用户名, 手机号, 邮箱, 邮箱是否激活)
        ① 判断用户是否登录
        ② 获取用户信息并返回
        '''
        user = request.user

        # if not user.is_authenticated:
        #     return JsonResponse({
        #         'code': 0,
        #         'message': '用户未登录'
        #     })

        user = {
            'username': user.username,
            'mobile': user.mobile,
            'email': user.email,
            'email_active': user.email_active
        }

        return JsonResponse({
            'code': 0,
            'message': 'OK',
            'user': user
        })